{% extends "tutorial.html" %}

{% block headauthor %}Eric Bidelman <e.bidelman@chromium.org>{% endblock %}

{% block headtitle %}Lesen lokaler Dateien in JavaScript{% endblock %}
{% block pagetitle %}Lesen lokaler Dateien in JavaScript{% endblock %}
{% block head %}
<style>
.example {
  padding: 10px;
  border: 1px solid #ccc;
}
#drop_zone {
  border: 2px dashed #bbb;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  border-radius: 5px;
  padding: 25px;
  text-align: center;
  font: 20pt bold 'Vollkorn';
  color: #bbb;
}
.thumb {
  height: 75px;
  border: 1px solid #000;
  margin: 10px 5px 0 0;
}
#progress_bar {
  margin: 10px 0;
  padding: 3px;
  border: 1px solid #000;
  font-size: 14px;
  clear: both;
  opacity: 0;
  -o-transition: opacity 1s linear;
  -moz-transition: opacity 1s linear;
  -webkit-transition: opacity 1s linear;
}
#progress_bar.loading {
  opacity: 1.0;
}
#progress_bar .percent {
  background-color: #99ccff;
  height: auto;
  width: 0;
}
#byte_content {
  margin: 5px 0;
  max-height: 100px;
  overflow-y: auto;
  overflow-x: hidden;
}
#byte_range {
  margin-top: 5px;
}
</style>
{% endblock %}
{% block pagebreadcrumb %}Lesen lokaler Dateien in JavaScript{% endblock %}
{% block date %}18. Juni 2010{% endblock %}
{% block updated %}21. Dezember 2010{% endblock %}

{% block browsersupport %}
<span class="browser opera supported"><span class="browser_name">Opera</span><span class="support">unterstützt</span></span> <span class="browser ie"><span class="browser_name">Internet Explorer</span><span class="support">nicht unterstützt</span></span> <span class="browser safari"><span class="browser_name">Safari</span><span class="support">nicht unterstützt</span></span> <span class="browser ff supported"><span class="browser_name">Firefox</span><span class="support">unterstützt</span></span> <span class="browser chrome supported"><span class="browser_name">Chrome</span><span class="support">unterstützt</span></span>
{% endblock %}

{% block html5badge %}
<img src="/static/images/identity/html5-badge-h-performance.png" width="133" height="64" alt="Dieser Artikel wird unterstützt von HTML5 Performance &amp; Integration" title="Dieser Artikel wird unterstützt von HTML5 Performance &amp; Integration"  />
{% endblock %}

{% block iscompatible %}
  return !!(window.File) && !!(window.FileReader) && !!(window.FileList) && !!(window.Blob);
{% endblock %}

{% block content %}
  <h2 id="toc-introduction">Einführung</h2>

  <p>HTML5 bietet über die <a href="http://www.w3.org/TR/file-upload/">File API</a>-Spezifikation endlich eine Standardmethode für die Interaktion mit lokalen Dateien. Mit dem File API können Sie beispielsweise eine Miniaturansicht von Bildern in der Vorschau anzeigen, während diese an den Server gesendet werden, oder es einer App ermöglichen, einen Dateiverweis zu speichern, während der Nutzer offline ist. Außerdem können Sie mithilfe der clientseitigen Logik überprüfen, ob der Mimetyp eines Uploads mit seiner Dateiendung übereinstimmt, oder die Größe von Uploads beschränken.</p>
  <p>Die Spezifikation bietet verschiedene Schnittstellen zum Zugriff auf Dateien aus einem lokalen Dateisystem:</p>
  <ol>
    <li><code>File</code> - eine einzelne Datei. Stellt schreibgeschützte Informationen wie Name, Dateigröße, Mimetyp und einen Verweis auf den Dateihandle bereit.</li>
    <li><code>FileList</code> - eine arrayartige Folge von <code>File</code>-Objekten. (Denken Sie an <code>&lt;input type="file" multiple&gt;</code> oder das Ziehen eines Dateiverzeichnisses vom Desktop.)</li>
    <li><code>Blob</code> - ermöglicht das Unterteilen einer Datei in Bytebereiche.</li>
  </ol>
  <p>Bei Verwendung in Verbindung mit den obigen Datenstrukturen kann die <a href="http://dev.w3.org/2006/webapi/FileAPI/#filereader-interface"><code>FileReader</code></a>-Schnittstelle dazu genutzt werden, eine Datei über die vertraute JavaScript-Ereignisbehandlung asynchron zu lesen. Dadurch können Sie den Fortschritt eines Lesevorgangs überwachen, Fehler ermitteln und feststellen, wann ein Ladevorgang abgeschlossen ist. Die APIs ähneln in vielerlei Hinsicht dem <code>XMLHttpRequest</code>-Ereignismodell.</p>

  <p>Hinweis: Zum Zeitpunkt der Erstellung dieser Anleitung werden die erforderlichen APIs zur Arbeit mit lokalen Dateien in Chrome 6.0 und Firefox 3.6 unterstützt. Ab Firefox 3.6.3 wird die <code>File.slice()</code>-Methode nicht unterstützt.</p>

  <h2 id="toc-selecting-files">Auswählen von Dateien</h2>
  <p>Überprüfen Sie zunächst, ob Ihr Browser das File API vollständig unterstützt:</p>
  <pre class="prettyprint">// Check for the various File API support.
if (window.File && window.FileReader && window.FileList && window.Blob) {
  // Great success! All the File APIs are supported.
} else {
  alert('The File APIs are not fully supported in this browser.');
}
</pre>

  <p>Falls Ihre App nur einige dieser APIs verwendet, passen Sie dieses Snippet einfach entsprechend an.</p>

  <h3 id="toc-selecting-files-input">Verwenden der Formulareingabe für die Auswahl</h3>
  <p>Die einfachste Methode zum Laden einer Datei ist die Verwendung eines Standardelements vom Typ <code>&lt;input type="file"&gt;</code>. JavaScript gibt die Liste der ausgewählten <code>File</code>-Objekte als <code>FileList</code> zurück. Im folgenden Beispiel wird das "multiple"-Attribut verwendet, um die Auswahl mehrerer Dateien gleichzeitig zu ermöglichen:</p>
  <pre class="prettyprint">&lt;input type="file" id="files" name="files[]" multiple /&gt;
&lt;output id="list"&gt;&lt;/output&gt;

&lt;script&gt;
  function handleFileSelect(evt) {
    var files = evt.target.files; // FileList object

    // files is a FileList of File objects. List some properties.
    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
      output.push('&lt;li&gt;&lt;strong&gt;', escape(f.name), '&lt;/strong&gt; (', f.type || 'n/a', ') - ',
                  f.size, ' bytes, last modified: ',
                  f.lastModifiedDate.toLocaleDateString(), '&lt;/li&gt;');
    }
    document.getElementById('list').innerHTML = '&lt;ul&gt;' + output.join('') + '&lt;/ul&gt;';
  }

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
&lt;/script&gt;
</pre>

  <p><strong>Beispiel:</strong> Verwenden der Formulareingabe für die Auswahl. Probieren Sie es aus!</p>
  <div class="example">
    <input type="file" id="files1" name="files1[]" multiple />
    <output id="file_list"></output>
  </div>

  <h3 id="toc-selecting-files-dnd">Verwenden von Drag & Drop für die Auswahl</h3>
  <p>Eine andere Technik zum Laden von Dateien ist das native Drag & Drop vom Desktop in den Browser. Wir können unser vorheriges Beispiel leicht abändern, um den Drag & Drop-Support zu integrieren.</p>
  <pre class="prettyprint">&lt;div id="drop_zone">Drop files here&lt;/div&gt;
&lt;output id="list"&gt;&lt;/output&gt;

&lt;script&gt;
  function handleFileSelect(evt) {
    evt.stopPropagation();
    evt.preventDefault();

    var files = evt.dataTransfer.files; // FileList object.

    // files is a FileList of File objects. List some properties.
    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
      output.push('&lt;li&gt;&lt;strong&gt;', escape(f.name), '&lt;/strong&gt; (', f.type || 'n/a', ') - ',
                  f.size, ' bytes, last modified: ',
                  f.lastModifiedDate.toLocaleDateString(), '&lt;/li&gt;');
    }
    document.getElementById('list').innerHTML = '&lt;ul&gt;' + output.join('') + '&lt;/ul&gt;';
  }

  function handleDragOver(evt) {
    evt.stopPropagation();
    evt.preventDefault();
    evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
  }

  // Setup the dnd listeners.
  var dropZone = document.getElementById('drop_zone');
  dropZone.addEventListener('dragover', handleDragOver, false);
  dropZone.addEventListener('drop', handleFileSelect, false);
&lt;/script&gt;</pre>

  <p><strong>Beispiel:</strong> Verwenden von Drag & Drop für die Auswahl. Probieren Sie es aus!</p>
  <div class="example">
    <div id="drop_zone">Dateien hier ablegen</div>
    <output id="file_list2"></output>
  </div>

  <p>Hinweis: Einige Browser behandeln <code>&lt;input type="file"&gt;</code>-Elemente als native Drop-Ziele. Versuchen Sie, Dateien auf das Eingabefeld im vorherigen Beispiel zu ziehen.</p>

  <h2 id="toc-reading-files">Lesen von Dateien</h2>
  <p>Jetzt wird's interessant!</p>
  <p>Nachdem Sie einen <code>File</code>-Verweis abgerufen haben, instanziieren Sie ein <a href="http://dev.w3.org/2006/webapi/FileAPI/#filereader-interface"><code>FileReader</code></a>-Objekt, um den Inhalt in den Speicher zu lesen. Sobald der Ladevorgang abgeschlossen ist, wird das <code>onload</code>-Ereignis des Readers ausgelöst und das <code>result</code>-Attribut kann für den Zugriff auf die Dateidaten verwendet werden.</p>
  <p><code>FileReader</code> bietet vier Optionen zum asynchronen Lesen einer Datei:</p>
  <ul>
    <li><code>FileReader.readAsBinaryString(Blob|File)</code> - die <code>result</code>-Eigenschaft enthält die Datei-/Blob-Daten als binären String. Jedes Byte wird als Ganzzahl im Bereich [0..255] dargestellt.</li>
    <li><code>FileReader.readAsText(Blob|File, opt_encoding)</code> - die <code>result</code>-Eigenschaft enthält die Datei-/Blob-Daten als Textstring. Der String wird standardmäßig mit "UTF-8" entschlüsselt. Mit dem optionalen Codierungsparameter können Sie ein anderes Format angeben.</li>
    <li><code>FileReader.readAsDataURL(Blob|File)</code> - die <code>result</code>-Eigenschaft enthält die Datei-/Blob-Daten verschlüsselt als <a href="http://de.wikipedia.org/wiki/Data-URL">Data-URL</a>.</li>
    <li><code>FileReader.readAsArrayBuffer(Blob|File)</code> - die <code>result</code>-Eigenschaft enthält die Datei-/Blob-Daten als <a href="https://www.khronos.org/registry/typedarray/specs/latest/#5">ArrayBuffer</a>-Objekt.</li>
  </ul>

  <p>Eine dieser Lesemethoden wird auf Ihrem <code>FileReader</code>-Objekt aufgerufen. Mit <code>onloadstart</code>, <code>onprogress</code>, <code>onload</code>, <code>onabort</code>, <code>onerror</code> und <code>onloadend</code> kann der Fortschritt verfolgt werden.</p>
  
  <p>Im folgenden Beispiel werden Bilder aus der Auswahl des Nutzers herausgefiltert, <code>reader.readAsDataURL()</code> auf der Datei aufgerufen und eine Miniaturansicht durch Einstellen des "src"-Attributs auf eine Data-URL gerendert.</p>
  <pre class="prettyprint">&lt;style&gt;
  .thumb {
    height: 75px;
    border: 1px solid #000;
    margin: 10px 5px 0 0;
  }
&lt;/style&gt;

&lt;input type="file" id="files" name="files[]" multiple /&gt;
&lt;output id="list"&gt;&lt;/output&gt;

&lt;script&gt;
  function handleFileSelect(evt) {
    var files = evt.target.files; // FileList object

    // Loop through the FileList and render image files as thumbnails.
    for (var i = 0, f; f = files[i]; i++) {

      // Only process image files.
      if (!f.type.match('image.*')) {
        continue;
      }

      var reader = new FileReader();

      // Closure to capture the file information.
      reader.onload = (function(theFile) {
        return function(e) {
          // Render thumbnail.
          var span = document.createElement('span');
          span.innerHTML = ['&lt;img class="thumb" src="', e.target.result,
                            '" title="', escape(theFile.name), '"/&gt;'].join('');
          document.getElementById('list').insertBefore(span, null);
        };
      })(f);

      // Read in the image file as a data URL.
      reader.readAsDataURL(f);
    }
  }

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
&lt;/script&gt;</pre>

  <p><strong>Beispiel:</strong> Lesen von Dateien. Probieren Sie es aus!</p>
  <div class="example">
    <p>Testen Sie dieses Beispiel mit einem Bildverzeichnis!</p>
    <input type="file" id="files3" name="files3[]" multiple /><br>
    <output id="thumbnails"></output>
  </div>

  <h3 id="toc-slicing-files">Aufteilen einer Datei</h3>

  <p>Manchmal ist es nicht die beste Option, die gesamte Datei in den Speicher zu lesen. Angenommen, Sie möchten einen asynchronen Datei-Uploader erstellen. Eine Möglichkeit zur Beschleunigung des Uploads bestünde darin, die Datei in einzelnen Bytebereich-Stücken zu lesen und zu senden. Die Serverkomponente wäre dann dafür zuständig, den Dateiinhalt in der richtigen Reihenfolge wieder zusammenzusetzen.</p>
  <p>Glücklicherweise unterstützt die <code>File</code>-Schnittstelle eine Aufteilungsmethode für diesen Anwendungsfall. Diese Methode verwendet ein Startbyte als erstes Argument, ein Endbyte als zweites und einen optionalen Inhaltstyp-String als drittes Argument. Die Semantik dieser Methode hat sich vor Kurzem geändert, darum wurde ein Anbieter-Präfix hinzugefügt:</p>

  <pre class="prettyprint">
if (file.webkitSlice) {
  var blob = file.webkitSlice(<var>startingByte</var>, <var>endindByte</var>);
} else if (file.mozSlice) {
  var blob = file.mozSlice(<var>startingByte</var>, <var>endindByte</var>);
}
reader.readAsBinaryString(blob);</pre>

  <p>Im folgenden Beispiel ist das Lesen von Dateistücken dargestellt. Erwähnenswert ist, dass in dem Beispiel das <code>onloadend</code>-Ereignis verwendet und der <code>evt.target.readyState</code> überprüft wird, statt das <code>onload</code>-Ereignis zu verwenden.</p>

<pre class="prettyprint">&lt;style&gt;
  #byte_content {
    margin: 5px 0;
    max-height: 100px;
    overflow-y: auto;
    overflow-x: hidden;
  }
  #byte_range { margin-top: 5px; }
&lt;/style&gt;

&lt;input type="file" id="files" name="file" /&gt; Read bytes: 
&lt;span class="readBytesButtons"&gt;
  &lt;button data-startbyte="0" data-endbyte="4"&gt;1-5&lt;/button&gt;
  &lt;button data-startbyte="5" data-endbyte="14"&gt;6-15&lt;/button&gt;
  &lt;button data-startbyte="6" data-endbyte="7"&gt;7-8&lt;/button&gt;
  &lt;button&gt;entire file&lt;/button&gt;
&lt;/span&gt;
&lt;div id="byte_range"&gt;&lt;/div&gt;
&lt;div id="byte_content"&gt;&lt;/div&gt;

&lt;script&gt;
  function readBlob(opt_startByte, opt_stopByte) {

    var files = document.getElementById('files').files;
    if (!files.length) {
      alert('Please select a file!');
      return;
    }

    var file = files[0];
    var start = parseInt(opt_startByte) || 0;
    var stop = parseInt(opt_stopByte) || file.size - 1;

    var reader = new FileReader();

    // If we use onloadend, we need to check the readyState.
    reader.onloadend = function(evt) {
      if (evt.target.readyState == FileReader.DONE) { // DONE == 2
        document.getElementById('byte_content').textContent = evt.target.result;
        document.getElementById('byte_range').textContent = 
            ['Read bytes: ', start + 1, ' - ', stop + 1,
             ' of ', file.size, ' byte file'].join('');
      }
    };

    if (file.webkitSlice) {
      var blob = file.webkitSlice(start, stop + 1);
    } else if (file.mozSlice) {
      var blob = file.mozSlice(start, stop + 1);
    }
    reader.readAsBinaryString(blob);
  }
  
  document.querySelector('.readBytesButtons').addEventListener('click', function(evt) {
    if (evt.target.tagName.toLowerCase() == 'button') {
      var startByte = evt.target.getAttribute('data-startbyte');
      var endByte = evt.target.getAttribute('data-endbyte');
      readBlob(startByte, endByte);
    }
  }, false);
&lt;/script&gt;</pre>

  <p><strong>Beispiel:</strong> Aufteilen einer Datei. Probieren Sie es aus!</p>
  <div class="example">
    <input type="file" id="file4" name="file4" /> Bytes lesen: <span class="readBytesButtons">
      <button data-startbyte="0" data-endbyte="4">1 - 5</button>
      <button data-startbyte="5" data-endbyte="14">6 - 15</button>
      <button data-startbyte="6" data-endbyte="7">7 - 8</button>
      <button>gesamte Datei</button>
    </span>
    <div id="byte_range"></div>
    <div id="byte_content"></div>
  </div>

  <h3 id="toc-monitoring-progress">Überwachen des Lesefortschritts</h3>

  <p>Ein praktisches Extra, das wir beim Verwenden der asynchronen Ereignisbehandlung erhalten, ist die Möglichkeit der Überwachung des Lesefortschritts. Dies ist vor allem nützlich, um große Dateien zu lesen, Fehler zu erkennen und herauszufinden, wann der Lesevorgang abgeschlossen ist.</p>

  <p>Der Lesefortschritt kann mithilfe des <code>onloadstart</code>- und des <code>onprogress</code>-Ereignisses kontrolliert werden.</p>

  <p>Im folgenden Beispiel wird die Anzeige einer Statusleiste zur Überwachung eines Lesevorgangs dargestellt. Machen Sie einen Test mit einer großen Datei oder einer Datei von einem Remotelaufwerk, um die Statusleiste in Aktion zu sehen.</p>

<pre class="prettyprint">&lt;style&gt;
  #progress_bar {
    margin: 10px 0;
    padding: 3px;
    border: 1px solid #000;
    font-size: 14px;
    clear: both;
    opacity: 0;
    -moz-transition: opacity 1s linear;
    -o-transition: opacity 1s linear;
    -webkit-transition: opacity 1s linear;
  }
  #progress_bar.loading {
    opacity: 1.0;
  }
  #progress_bar .percent {
    background-color: #99ccff;
    height: auto;
    width: 0;
  }
&lt;/style&gt;

&lt;input type="file" id="files" name="file" /&gt;
&lt;button onclick="abortRead();"&gt;Cancel read&lt;/button&gt;
&lt;div id="progress_bar"&gt;&lt;div class="percent"&gt;0%&lt;/div&gt;&lt;/div&gt;

&lt;script&gt;
  var reader;
  var progress = document.querySelector('.percent');

  function abortRead() {
    reader.abort();
  }

  function errorHandler(evt) {
    switch(evt.target.error.code) {
      case evt.target.error.NOT_FOUND_ERR:
        alert('File Not Found!');
        break;
      case evt.target.error.NOT_READABLE_ERR:
        alert('File is not readable');
        break;
      case evt.target.error.ABORT_ERR:
        break; // noop
      default:
        alert('An error occurred reading this file.');
    };
  }

  function updateProgress(evt) {
    // evt is an ProgressEvent.
    if (evt.lengthComputable) {
      var percentLoaded = Math.round((evt.loaded / evt.total) * 100);
      // Increase the progress bar length.
      if (percentLoaded &lt; 100) {
        progress.style.width = percentLoaded + '%';
        progress.textContent = percentLoaded + '%';
      }
    }
  }

  function handleFileSelect(evt) {
    // Reset progress indicator on new file selection.
    progress.style.width = '0%';
    progress.textContent = '0%';

    reader = new FileReader();
    reader.onerror = errorHandler;
    reader.onprogress = updateProgress;
    reader.onabort = function(e) {
      alert('File read cancelled');
    };
    reader.onloadstart = function(e) {
      document.getElementById('progress_bar').className = 'loading';
    };
    reader.onload = function(e) {
      // Ensure that the progress bar displays 100% at the end.
      progress.style.width = '100%';
      progress.textContent = '100%';
      setTimeout("document.getElementById('progress_bar').className='';", 2000);
    }

    // Read in the image file as a binary string.
    reader.readAsBinaryString(evt.target.files[0]);
  }

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
&lt;/script&gt;</pre>

  <p><strong>Beispiel:</strong> Überwachen des Lesefortschritts. Probieren Sie es aus!</p>
  <div class="example">
    <input type="file" id="file5" name="file5" />
    <button onclick="example5.abortRead();">Lesen abbrechen</button>
    <div id="progress_bar"><div class="percent">0 %</div></div>
    <p><strong>Tipp:</strong> Verwenden Sie eine große Datei oder eine Ressource von einem Remotelaufwerk, um die Statusleiste in Aktion zu sehen.</p>
  </div>

  <h2 id="toc-references">Referenzen</h2>
  <ul>
    <li><a href="http://www.w3.org/TR/file-upload/">File API</a>-Spezifikation</li>
    <li><a href="http://www.w3.org/TR/file-upload/#dfn-filereader">FileReader</a>-Schnittstellenspezifikation</li>
    <li><a href="http://www.w3.org/TR/file-upload/#dfn-Blob">Blob</a>-Schnittstellenspezifikation</li>
    <li><a href="http://www.w3.org/TR/file-upload/#dfn-fileerror">FileError</a>-Schnittstellenspezifikation</li>
    <li><a href="http://www.w3.org/TR/progress-events/#Progress">ProgressEvent</a>-Spezifikation</li>
  </ul>

<script>
var get = function(id) { return document.getElementById(id); }

var example1 = example1 || {};
example1.handleFileSelect = function(evt) {
  var files = evt.target.files;
  var output = [];
  for (var i = 0, f; f = files[i]; i++) {
    output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
                f.size, ' bytes, last modified: ',
                f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
                '</li>');
  }
  get('file_list').innerHTML = '<ul>' + output.join('') + '</ul>';
}
get('files1').addEventListener('change', example1.handleFileSelect, false);

var example2 = example2 || {};
example2.onDragOver = function(evt) {
  evt.stopPropagation();
  evt.preventDefault();
  evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
}

example2.onDragFileDrop = function(evt) {
  evt.stopPropagation();
  evt.preventDefault();

  var files = evt.dataTransfer.files;
  var output = [];
  for (var i = 0, f; f = files[i]; i++) {
    output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
                f.size, ' bytes, last modified: ',
                f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
                '</li>');
  }
  get('file_list2').innerHTML = '<ul>' + output.join('') + '</ul>';
}

// Setup the dnd listeners.
get('drop_zone').addEventListener('dragover', example2.onDragOver, false);
get('drop_zone').addEventListener('drop', example2.onDragFileDrop, false);


var example3 = example3 || {};
example3.handleFileSelect = function(evt) {
  var files = evt.target.files; // FileList object.

  // Loop through the FileList and render image files as thumbnails.
  for (var i = 0, f; f = files[i]; i++) {

    // Only process image files.
    if (!f.type.match('image.*')) {
      continue;
    }

    var reader = new FileReader();

    // Need a closure to capture the file information.
    reader.onload = (function(theFile) {
      return function(e) {
        // Render thumbnail.
        var span = document.createElement('span');
        span.innerHTML = ['<img class="thumb" src="', e.target.result,
                          '" title="', escape(theFile.name), '"/>'].join('');
        get('thumbnails').insertBefore(span, null);
      };
    })(f);

    // Read in the image file as a data URL.
    reader.readAsDataURL(f);
  }
}
get('files3').addEventListener('change', example3.handleFileSelect, false);

var example4 = example4 || {};
example4.readBlob = function(opt_startByte, opt_stopByte) {
  var files = get('file4').files;
  if (!files.length) {
    alert('Please select a file!');
    return;
  }

  var file = files[0];
  var start = parseInt(opt_startByte) || 0;
  var stop = parseInt(opt_stopByte) || file.size - 1;

  var reader = new FileReader();

  reader.onloadend = function(evt) {
    if (evt.target.readyState == FileReader.DONE) { // DONE == 2
      get('byte_content').textContent = evt.target.result;
      get('byte_range').textContent = ['Read bytes: ', start + 1, ' - ', stop + 1,
                                       ' of ', file.size, ' byte file'].join('');
    }
  };
  //var blob = file.slice(start, (stop - start) + 1);
  if (file.webkitSlice) {
    var blob = file.webkitSlice(start, stop + 1);
  } else if (file.mozSlice) {
    var blob = file.mozSlice(start, stop + 1);
  }
  reader.readAsBinaryString(blob);
};
document.querySelector('.readBytesButtons').addEventListener('click', function(evt) {
  if (evt.target.tagName.toLowerCase() == 'button') {
    var startByte = evt.target.getAttribute('data-startbyte');
    var stopByte = evt.target.getAttribute('data-endbyte');
    example4.readBlob(startByte, stopByte);
  }
}, false);

function Example5(id) {
  var reader_;
  var progress_ = document.querySelector('.percent');
  var self = this;

  this.abortRead = function() {
    reader_.abort();
  };

  this.errorHandler = function(evt) {
    switch(evt.target.error.code) {
      case evt.target.error.NOT_FOUND_ERR:
        alert('File Not Found!');
        break;
      case evt.target.error.NOT_READABLE_ERR:
        alert('File is not readable');
        break;
      case evt.target.error.ABORT_ERR:
        break; // noop
      default:
        alert('An error occurred reading this file.');
    };
  };

  this.updateProgress = function(evt) {
    // evt is a ProgressEvent.
    if (evt.lengthComputable) {
      var percentLoaded = Math.round((evt.loaded / evt.total) * 100);
      // Increase the progress bar length.
      if (percentLoaded < 100) {
        progress_.style.width = percentLoaded + '%';
        progress_.textContent = percentLoaded + '%';
      }
    }
  };

  this.handleFileSelect = function(evt) {
    // Reset progress indicator on new file selection.
    progress_.style.width = '0%';
    progress_.textContent = '0%';

    reader_ = new FileReader();
    reader_.onerror = self.errorHandler;
    reader_.onprogress = self.updateProgress;
    reader_.onabort = function(e) {
      alert('File read cancelled');
    };
    reader_.onloadstart = function(e) {
      get('progress_bar').className = 'loading';
    };
    reader_.onload = function(e) {
      // Ensure that the progress bar displays 100% at the end.
      progress_.style.width = '100%';
      progress_.textContent = '100%';
      setTimeout("get('progress_bar').className='';", 2000);
    }

    // Read in the image file as binary string.
    reader_.readAsBinaryString(evt.target.files[0]);
  };

  get(id).addEventListener('change', self.handleFileSelect, false);
};
var example5 = new Example5('file5');
</script>

{% endblock %}